use crate::loadbalancer::LoadBalancerManager;
use crate::strategies::{Random, RoundRobin, WeightedRoundRobin, ConsistentHash};
use rustcloud_core::{LoadBalancer, LoadBalancerStrategy, ServiceInstance};

#[tokio::test]
async fn test_round_robin_load_balancer() {
    let instances = vec![
        ServiceInstance::new("test", "localhost", 8080, "http"),
        ServiceInstance::new("test", "localhost", 8081, "http"),
    ];
    let lb = RoundRobin::new();
    let instance1 = lb.select("test", &instances).await.unwrap().unwrap();
    assert_eq!(instance1.port, 8080);
    let instance2 = lb.select("test", &instances).await.unwrap().unwrap();
    assert_eq!(instance2.port, 8081);
    let instance3 = lb.select("test", &instances).await.unwrap().unwrap();
    assert_eq!(instance3.port, 8080);
}

#[tokio::test]
async fn test_random_load_balancer() {
    let instances = vec![
        ServiceInstance::new("test", "localhost", 8080, "http"),
        ServiceInstance::new("test", "localhost", 8081, "http"),
    ];
    let lb = Random::new();
    let instance = lb.select("test", &instances).await.unwrap().unwrap();
    assert!(instance.port == 8080 || instance.port == 8081);
}

#[tokio::test]
async fn test_weighted_round_robin_load_balancer() {
    let mut instances = vec![
        ServiceInstance::new("test", "localhost", 8080, "http"),
        ServiceInstance::new("test", "localhost", 8081, "http"),
    ];
    
    // 设置权重
    instances[0].weight = 3.0;
    instances[1].weight = 1.0;
    
    let lb = WeightedRoundRobin::new();
    
    // 多次选择，验证权重生效
    let mut port_8080_count = 0;
    let mut port_8081_count = 0;
    
    for _ in 0..100 {
        let instance = lb.select("test", &instances).await.unwrap().unwrap();
        if instance.port == 8080 {
            port_8080_count += 1;
        } else if instance.port == 8081 {
            port_8081_count += 1;
        }
    }
    
    // 权重3:1，8080应该被选中更多次
    assert!(port_8080_count > port_8081_count);
}

#[tokio::test]
async fn test_consistent_hash_load_balancer() {
    let instances = vec![
        ServiceInstance::new("test", "localhost", 8080, "http"),
        ServiceInstance::new("test", "localhost", 8081, "http"),
        ServiceInstance::new("test", "localhost", 8082, "http"),
    ];
    
    let lb = ConsistentHash::new();
    
    // 同一个服务名应该总是选择同一个实例
    let instance1 = lb.select("test-service", &instances).await.unwrap().unwrap();
    let instance2 = lb.select("test-service", &instances).await.unwrap().unwrap();
    let instance3 = lb.select("test-service", &instances).await.unwrap().unwrap();
    
    assert_eq!(instance1.port, instance2.port);
    assert_eq!(instance2.port, instance3.port);
    
    // 不同服务名可能选择不同实例
    let instance_a = lb.select("service-a", &instances).await.unwrap().unwrap();
    let instance_b = lb.select("service-b", &instances).await.unwrap().unwrap();
    
    // 验证实例都在列表中
    assert!(instances.iter().any(|i| i.port == instance_a.port));
    assert!(instances.iter().any(|i| i.port == instance_b.port));
}

#[tokio::test]
async fn test_load_balancer_manager() {
    let instances = vec![
        ServiceInstance::new("test", "localhost", 8080, "http"),
        ServiceInstance::new("test", "localhost", 8081, "http"),
    ];
    let mut lb_manager = LoadBalancerManager::new(LoadBalancerStrategy::RoundRobin);
    let instance1 = lb_manager.select("test", &instances).await.unwrap().unwrap();
    assert_eq!(instance1.port, 8080);

    lb_manager.set_strategy(LoadBalancerStrategy::Random);
    let instance2 = lb_manager.select("test", &instances).await.unwrap().unwrap();
    assert!(instance2.port == 8080 || instance2.port == 8081);
    
    // 测试获取策略
    assert_eq!(lb_manager.get_strategy(), LoadBalancerStrategy::Random);
}

#[tokio::test]
async fn test_load_balancer_empty_list() {
    let instances = vec![];
    let lb_manager = LoadBalancerManager::new(LoadBalancerStrategy::RoundRobin);
    let result = lb_manager.select("test", &instances).await.unwrap();
    assert!(result.is_none());

    let lb_random = Random::new();
    let result_random = lb_random.select("test", &instances).await.unwrap();
    assert!(result_random.is_none());
    
    let lb_weighted = WeightedRoundRobin::new();
    let result_weighted = lb_weighted.select("test", &instances).await.unwrap();
    assert!(result_weighted.is_none());
    
    let lb_consistent = ConsistentHash::new();
    let result_consistent = lb_consistent.select("test", &instances).await.unwrap();
    assert!(result_consistent.is_none());
}

#[tokio::test]
async fn test_load_balancer_single_instance() {
    let instances = vec![ServiceInstance::new("test", "localhost", 8888, "http")];
    let lb_manager = LoadBalancerManager::new(LoadBalancerStrategy::RoundRobin);
    let instance = lb_manager.select("test", &instances).await.unwrap().unwrap();
    assert_eq!(instance.port, 8888);

    let lb_random = Random::new();
    let instance_random = lb_random.select("test", &instances).await.unwrap().unwrap();
    assert_eq!(instance_random.port, 8888);
}

#[tokio::test]
async fn test_load_balancer_unhealthy_instances() {
    let mut instances = vec![
        ServiceInstance::new("test", "localhost", 8080, "http"),
        ServiceInstance::new("test", "localhost", 8081, "http"),
        ServiceInstance::new("test", "localhost", 8082, "http"),
    ];
    
    // 将前两个实例标记为不健康
    instances[0].healthy = false;
    instances[1].healthy = false;
    
    let lb = RoundRobin::new();
    let instance = lb.select("test", &instances).await.unwrap().unwrap();
    // 只有第三个实例是健康的
    assert_eq!(instance.port, 8082);
    
    let lb_random = Random::new();
    let instance_random = lb_random.select("test", &instances).await.unwrap().unwrap();
    assert_eq!(instance_random.port, 8082);
}

#[tokio::test]
async fn test_load_balancer_all_unhealthy() {
    let mut instances = vec![
        ServiceInstance::new("test", "localhost", 8080, "http"),
        ServiceInstance::new("test", "localhost", 8081, "http"),
    ];
    
    // 将所有实例标记为不健康
    instances[0].healthy = false;
    instances[1].healthy = false;
    
    let lb = RoundRobin::new();
    let result = lb.select("test", &instances).await.unwrap();
    assert!(result.is_none());
}

#[tokio::test]
async fn test_load_balancer_strategy_names() {
    let lb_rr = RoundRobin::new();
    assert_eq!(lb_rr.name(), "round_robin");
    
    let lb_random = Random::new();
    assert_eq!(lb_random.name(), "random");
    
    let lb_weighted = WeightedRoundRobin::new();
    assert_eq!(lb_weighted.name(), "weighted_round_robin");
    
    let lb_consistent = ConsistentHash::new();
    assert_eq!(lb_consistent.name(), "consistent_hash");
}

#[tokio::test]
async fn test_consistent_hash_with_virtual_nodes() {
    let instances = vec![
        ServiceInstance::new("test", "localhost", 8080, "http"),
        ServiceInstance::new("test", "localhost", 8081, "http"),
    ];
    
    let lb = ConsistentHash::with_virtual_nodes(320);
    
    // 测试一致性
    let instance1 = lb.select("consistent-test", &instances).await.unwrap().unwrap();
    let instance2 = lb.select("consistent-test", &instances).await.unwrap().unwrap();
    
    assert_eq!(instance1.port, instance2.port);
}

#[tokio::test]
async fn test_weighted_round_robin_zero_weights() {
    let mut instances = vec![
        ServiceInstance::new("test", "localhost", 8080, "http"),
        ServiceInstance::new("test", "localhost", 8081, "http"),
    ];
    
    // 设置权重为0
    instances[0].weight = 0.0;
    instances[1].weight = 0.0;
    
    let lb = WeightedRoundRobin::new();
    let instance = lb.select("test", &instances).await.unwrap().unwrap();
    
    // 应该回退到随机选择
    assert!(instance.port == 8080 || instance.port == 8081);
}